#include "ConfigServer.h"
#include "ConfigApi.h"
#include "ProtocolApi.h"

ConfigServer *ConfigServer::s_configServer = nullptr;

using namespace Fdt;
using namespace ConfigApi;
using namespace Protocol;


ConfigServer::ConfigServer(){
	RegistRPC();
}


void ConfigServer::RegistRPC(){
	RPCMethodMap method_map;
	method_map.emplace("Set", CRPCFuntion::CreateRpc([this](const Json::Value &request, const BufferMap::Ptr &inMap, Json::Value &response, BufferMap::Ptr &outMap){
		return Set(request, inMap, response, outMap);
	}));
	
	method_map.emplace("Get", CRPCFuntion::CreateRpc([this](const Json::Value &request, const BufferMap::Ptr &inMap, Json::Value &response, BufferMap::Ptr &outMap){
		return Get(request, inMap, response, outMap);
	}));

    method_map.emplace("SetMulti", CRPCFuntion::CreateRpc([this](const Json::Value &request, const BufferMap::Ptr &inMap, Json::Value &response, BufferMap::Ptr &outMap){
		return SetMulti(request, inMap, response, outMap);
	}));

	method_map.emplace("GetMulti", CRPCFuntion::CreateRpc([this](const Json::Value &request, const BufferMap::Ptr &inMap, Json::Value &response, BufferMap::Ptr &outMap){
		return GetMulti(request, inMap, response, outMap);
	}));

	method_map.emplace("RestoreAll", CRPCFuntion::CreateRpc([this](const Json::Value &request, const BufferMap::Ptr &inMap, Json::Value &response, BufferMap::Ptr &outMap){
		return RestoreAll(request, inMap, response, outMap);
	}));

	method_map.emplace("GetDefault", CRPCFuntion::CreateRpc([this](const Json::Value &request, const BufferMap::Ptr &inMap, Json::Value &response, BufferMap::Ptr &outMap){
		return GetDefault(request, inMap, response, outMap);
	}));

	method_map.emplace("Restore", CRPCFuntion::CreateRpc([this](const Json::Value &request, const BufferMap::Ptr &inMap, Json::Value &response, BufferMap::Ptr &outMap){
		return Restore(request, inMap, response, outMap);
	}));

	method_map.emplace("RestoreMulti", CRPCFuntion::CreateRpc([this](const Json::Value &request, const BufferMap::Ptr &inMap, Json::Value &response, BufferMap::Ptr &outMap){
		return RestoreMulti(request, inMap, response, outMap);
	}));

	method_map.emplace("Subscribe", CRPCFuntion::CreateRpc([this](const Json::Value &request, const BufferMap::Ptr &inMap, Json::Value &response, BufferMap::Ptr &outMap){
		return Subscribe(request, inMap, response, outMap);
	}));

	IProtocolInterface::GetInstance()->RegistProtocol("Config", method_map);
}


bool ConfigServer::Set(const Json::Value &request, const BufferMap::Ptr &inMap, Json::Value &response, BufferMap::Ptr &outMap){

	if(!request.isMember("Param")){
		response["code"] = API::InvalidArgs;
		response["msg"] = "InvalidArgs";
		return false;
	}
    Json::Value Name = Json::Path("Param.Name").resolve(request, Json::Value::null);
    std::string name;
    if(Name.isString()){
    	name = Name.asString();
    }
    else{
    	response["code"] = API::InvalidArgs;
    	response["msg"] = "InvalidArgs";
		return false;
    }
    Json::Value Config = Json::Path("Param.Config").resolve(request, Json::Value::null);
    if(Config.isNull()){
    	response["code"] = API::InvalidArgs;
    	response["msg"] = "InvalidArgs";
		return false;
    }
    int result = 0;
    response["data"]["Param"]["Name"] = name;

    int option = 0;
    if(request["Param"].isMember("Option") && request["Param"]["Option"].isInt()){
    	option = request["Param"]["Option"].asInt();
    }
    if(IConfigInterface::GetInstance()->Set(name.c_str(), Config, option, result)){
    	response["data"]["Param"]["Result"] = true;
    	response["data"]["Param"]["Status"] = IConfigInterface::Status(result);
    	return true;
    }

    response["code"] = API::OptFailed;
    response["msg"] = "OptFailed";
    response["data"]["Param"]["Result"] = false;
    response["data"]["Param"]["Status"] = IConfigInterface::Status(result);
	return false;
}

bool ConfigServer::Get(const Json::Value &request, const BufferMap::Ptr &inMap, Json::Value &response, BufferMap::Ptr &outMap){
	//tracef("ConfigServer::Get");
	if(!request.isMember("Param")){
		tracef("ConfigServer::Get");
		response["code"] = API::InvalidArgs;
		response["msg"] = "InvalidArgs";
		return false;
	}
    Json::Value Name = Json::Path("Param.Name").resolve(request, Json::Value::null);
    std::string name;
    if(Name.isString()){
    	name = Name.asString();
    }
    else{
    	tracef("ConfigServer::Get");
    	response["code"] = API::InvalidArgs;
    	response["msg"] = API::InvalidArgs;
		return false;
    }
    //tracef("ConfigServer::Get");
    int result = 0;
    Json::Value Config;
    response["data"]["Param"]["Name"] = name;
    if(IConfigInterface::GetInstance()->Get(name.c_str(), Config, result)){
    	response["data"]["Param"]["Config"] = Config;
    	response["data"]["Param"]["Result"] = true;
    	response["data"]["Param"]["Status"] = IConfigInterface::Status(result);
    	return true;
    }
    else{
    	tracef("ConfigServer::Get");
    	tracef("Config Get failed");
    	response["code"] = API::OptFailed;
    	response["msg"] = "OptFailed";
    	response["data"]["Param"]["Result"] = false;
    	response["data"]["Param"]["Status"] = IConfigInterface::Status(result);
    }
    tracef("ConfigServer::Get");
    return false;
}

bool ConfigServer::SetMulti(const Json::Value &request, const BufferMap::Ptr &inMap, Json::Value &response, BufferMap::Ptr &outMap){
	if(!request.isMember("Param") || !request["Param"].isArray()){
		response["code"] = API::InvalidArgs;
		return false;
	}

	int result = 0;
	const Json::Value &table = Json::Path("Param").resolve(request);
	for(uint i = 0; i < table.size(); i++){
		if(!(table[i].isMember("Name") && table[i]["Name"].isString())){
			continue;
		}
		if(!(table[i].isMember("Config"))){
			continue;
		}
		int option = 0;
		if(table[i].isMember("Option") && table[i]["Option"].isInt()){
			option = table[i]["Option"].asInt();
		}
		if(i+1 == table.size()){
			if(result & ConfigApi::ConfigResultChanged){//如过最后一个之前有变更,那么最后一项强制保�?
				option |= ConfigApi::ConfigOptionForceSave;
			}
		}
		else{
			option |= ConfigApi::ConfigOptionDelaySave;
		}

		response["Param"][i]["Name"] = table[i]["Name"];
		if(IConfigInterface::GetInstance()->Set(table[i]["Name"].asCString(), table[i]["Config"], option, result)){
			response["data"]["Param"][i]["Result"] = true;
			response["data"]["Param"][i]["Status"] = IConfigInterface::Status(result);
		}
		else{
			response["data"]["Param"][i]["Result"] = false;
			response["data"]["Param"][i]["Status"] = IConfigInterface::Status(result);
		}
	}

	return true;
}

bool ConfigServer::GetMulti(const Json::Value &request, const BufferMap::Ptr &inMap, Json::Value &response, BufferMap::Ptr &outMap){
	if(!request.isMember("Param") || !request["Param"].isArray()){
		response["code"] = API::InvalidArgs;
		response["msg"] = API::InvalidArgs;
		return false;
	}

	int result = 0;
	const Json::Value &table = Json::Path("Param").resolve(request);
	for(uint i = 0; i < table.size(); i++){
		if(!(table[i].isMember("Name") && table[i]["Name"].isString())){
			continue;
		}

		response["data"]["Param"][i]["Name"] = table[i]["Name"];
		Json::Value config;
		if(IConfigInterface::GetInstance()->Get(table[i]["Name"].asCString(), config, result)){
			response["data"]["Param"][i]["Result"] = true;
			response["data"]["Param"][i]["Config"] = config;
			response["data"]["Param"][i]["Status"] = IConfigInterface::Status(result);
		}
		else{
			response["data"]["Param"][i]["Result"] = false;
			response["data"]["Param"][i]["Status"] = IConfigInterface::Status(result);
		}
	}

	return true;
}

bool ConfigServer::RestoreAll(const Json::Value &request, const BufferMap::Ptr &inMap, Json::Value &response, BufferMap::Ptr &outMap){
	response["data"]["Param"]["Result"] = true;
	return true;
}

bool ConfigServer::GetDefault(const Json::Value &request, const BufferMap::Ptr &inMap, Json::Value &response, BufferMap::Ptr &outMap){
	return true;
}

bool ConfigServer::Restore(const Json::Value &request, const BufferMap::Ptr &inMap, Json::Value &response, BufferMap::Ptr &outMap){
	if(!request.isMember("Param")){
		response["code"] = API::InvalidArgs;
		response["msg"] = "InvalidArgs";
		return false;
	}
    Json::Value Name = Json::Path("Param.Name").resolve(request, Json::Value::null);
    std::string name;
    if(Name.isString()){
    	name = Name.asString();
    }
    else{
    	response["code"] = API::InvalidArgs;
    	response["msg"] = "InvalidArgs";
		return false;
    }
    int result = 0;
    response["data"]["Param"]["Name"] = name;
    if(IConfigInterface::GetInstance()->Restore(name.c_str(), 0, result)){

    	response["data"]["Param"]["Result"] = true;
    	response["data"]["Param"]["Status"] = IConfigInterface::Status(result);
    	return true;
    }
    response["code"] = API::OptFailed;
    response["msg"] = "OptFailed";
    response["data"]["Param"]["Result"] = false;
    response["data"]["Param"]["Status"] = IConfigInterface::Status(result);
	return false;
}


bool ConfigServer::RestoreMulti(const Json::Value &request, const BufferMap::Ptr &inMap, Json::Value &response, BufferMap::Ptr &outMap){
	if(!request.isMember("Param") || !request["Param"].isArray()){
		response["code"] = API::InvalidArgs;
		return false;
	}

	int result = 0;

	const Json::Value &table = Json::Path("Param").resolve(request);
	for(uint i = 0; i < table.size(); i++){
		if(!(table[i].isMember("Name") && table[i]["Name"].isString())){
			continue;
		}

		int option = 0;
		if(i+1 == table.size()){
			if(result & ConfigApi::ConfigResultChanged){//如过最后一个之前有变更,那么最后一项强制保�?
				option |= ConfigApi::ConfigOptionForceSave;
			}
		}
		else{
			option |= ConfigApi::ConfigOptionDelaySave;
		}
		response["data"]["Param"][i]["Name"] = table[i]["Name"];
		if(IConfigInterface::GetInstance()->Restore(table[i]["Name"].asCString(), option, result)){
			response["data"]["Param"][i]["Result"] = true;
			response["data"]["Param"][i]["Status"] = IConfigInterface::Status(result);
		}
		else{
			response["data"]["Param"][i]["Result"] = false;
			response["data"]["Param"][i]["Status"] = IConfigInterface::Status(result);
		}
	}

	return true;
}

bool ConfigServer::Subscribe(const Json::Value &request, const Fdt::BufferMap::Ptr &inMap, 
		Json::Value &response, Fdt::BufferMap::Ptr &outMap){
	if(!request.isMember("Param") || !request["Param"].isMember("NameList") || 
		!request["Param"]["NameList"].isArray()){
		response["code"] = API::InvalidArgs;
		return false;
	}

	const Json::Value &table = request["Param"]["NameList"];
	for(uint i = 0; i < table.size(); i++){
		if(!(table[i].isMember("Name") && table[i]["Name"].isString())){
			continue;
		}
		IConfigInterface::GetInstance()->Attach(table[i]["Name"].asString(), this, 
		[this](const std::string &name, const Json::Value &newTable, 
				const Json::Value &oldTable, int &result){

			Json::Value notifyReq;
			notifyReq["notify"]["Class"] = "Config";
			notifyReq["notify"]["Method"] = "Subscribe";
			notifyReq["notify"]["Param"]["Name"] = name;
			notifyReq["notify"]["Param"]["Config"] = newTable;
			return IConfigInterface::GetInstance()->CallNotifyFunc(notifyReq);
		});
	}

    return true;
}